package cn.siat.gene.controller;

import cn.siat.common.core.domain.R;
import cn.siat.common.core.utils.StringUtils;
import cn.siat.common.core.web.controller.BaseController;
import cn.siat.common.core.web.domain.AjaxResult;
import cn.siat.common.core.web.page.TableDataInfo;
import cn.siat.common.log.annotation.Log;
import cn.siat.common.log.enums.BusinessType;
import cn.siat.common.security.annotation.RequiresPermissions;
import cn.siat.gene.constant.OperateEnum;
import cn.siat.gene.domain.Feature;
import cn.siat.gene.domain.Programme;
import cn.siat.gene.domain.Sequence;
import cn.siat.gene.domain.SequenceOperate;
import cn.siat.gene.model.Annotation;
import cn.siat.gene.model.Location;
import cn.siat.gene.model.Pack;
import cn.siat.gene.service.*;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@RequestMapping("/sequence")
@RestController
@RequiredArgsConstructor
@Slf4j
public class SequenceController  extends BaseController {
    private final SequenceService sequenceService;
    private final SequenceOperateService sequenceOperateService;
    private final IProgrammeService programmeService;
    private final FeatureService featureService;
    private final MinioFileService minioFileService;
    @ApiOperation(value = "保存序列")
    @PostMapping(value = "/save")
    @Log(title = "保存序列", businessType = BusinessType.INSERT)
    public AjaxResult cutSequence(@RequestBody String[] sourceFileNames,String programmeId,Integer chooseFile) throws IOException {
        if(sourceFileNames.length==2 && (sourceFileNames[0].endsWith("txt") ||sourceFileNames[1].endsWith("txt"))){
            String configFile,gbFile;
            if(sourceFileNames[0].endsWith("txt")){
                configFile = sourceFileNames[0];
                gbFile = sourceFileNames[1];
            }else{
                configFile = sourceFileNames[1];
                gbFile = sourceFileNames[0];
            }
            String result = sequenceService.historyPreprocessing(configFile,gbFile,programmeId);
            if(result.length()>50){
                return AjaxResult.error("历史文件转换失败");
            }
            sourceFileNames[0] = result;
            sourceFileNames[1] = gbFile;
        }
        AjaxResult ajaxResult = sequenceService.cutSequenceFile(sourceFileNames,programmeId);
        if(ajaxResult.isSuccess() && Integer.valueOf(1).equals(chooseFile) ){
            sequenceService.checkChooseFileSequence((List<Sequence>)ajaxResult.getData());
            ajaxResult.put("chooseFile",1);
        }
        return ajaxResult;
    }
    @ApiOperation(value = "从minio上下载至服务器文件夹")
    @PostMapping(value = "/downLoadToServer")
    public AjaxResult downLoadToServer(@RequestBody List<Long> idList,String programmeId) {
        return AjaxResult.success(minioFileService.downLoadToServer(idList, sequenceService.getSequenceFolderPath(programmeId)));
    }

    @Log(title = "取消保存序列", businessType = BusinessType.DELETE)
    @ApiOperation(value = "取消保存序列")
    @DeleteMapping(value = "/cancel")
    public AjaxResult cancelCutSequence(String programmeId) throws IOException {
        sequenceService.removeProcessCache(programmeId);
        return AjaxResult.success();
    }
    @Log(title = "序列列表", businessType = BusinessType.VIEWED)
    @ApiOperation(value = "序列列表")
    @GetMapping(value = "/list")
    public AjaxResult listSequence(String programmeId) {
        return AjaxResult.success(sequenceService.listSequence(new Sequence().setProgrammeId(programmeId)));
    }
    @ApiOperation(value = "新建feature")
    @PostMapping(value = "/saveFeatureList")
    public AjaxResult saveFeatureList(@RequestBody  List<Feature> list){
        return featureService.saveFeatureList(list);
    }
    @Log(title = "新建/修改feature", businessType = BusinessType.INSERT)
    @ApiOperation(value = "新建/修改feature")
    @PostMapping(value = "/saveOrUpdateFeature")
    public AjaxResult saveFeature(@RequestBody Feature feature){
        if(feature.getId()==null){
            List<Feature> list = new ArrayList<>();
            list.add(feature);
            return featureService.saveFeatureList(list);
        }else{
            return featureService.updateFeature(feature);
        }
    }
    @Log(title = "删除feature", businessType = BusinessType.DELETE)
    @ApiOperation(value = "删除feature")
    @PostMapping(value = "/removeFeatureList")
    public AjaxResult removeFeatureList(@RequestBody List<Long> list,Long sequenceId){
        return toAjax(featureService.removeFeatureList(sequenceId,list));
    }
    @Log(title = "序列列表", businessType = BusinessType.VIEWED)
    @ApiOperation(value = "序列列表,按文件划分")
    @GetMapping(value = "/list/file")
    public AjaxResult listFileSequence(String programmeId,String name,Integer start) throws IOException {
        List<Sequence> list =sequenceService.listSequence(new Sequence().setProgrammeId(programmeId).setName(name));
        // 跟annoation对应上
        Programme programme = programmeService.getById(list.get(0).getProgrammeId());
        List<Annotation> annotationList = programme.getAnnotationList();
        List<Sequence> result = new ArrayList<>();
        for (Sequence sequence : list) {
            AjaxResult ajaxResult = sequenceService.getSequence(sequence.setStart(start));
            if(ajaxResult.isSuccess()){
                Sequence seq = (Sequence) ajaxResult.getData();
                Annotation annotation = annotationList.get(annotationList.indexOf(new Annotation(seq.getSourceFileName())));
                String source;
                if(StringUtils.isNotEmpty(annotation.getSource())){
                    source = annotation.getSource();
                }else if(StringUtils.isNotEmpty(annotation.getKeyWords())){
                    source = annotation.getKeyWords();
                }else{
                    source = annotation.getSourceFileName();
                }
                result.add(seq.setSource(source));
            }else{
                return ajaxResult;
            }
        }
        return AjaxResult.success(result);
    }
    @Log(title = "序列详情", businessType = BusinessType.VIEWED)
    @ApiOperation(value = "序列")
    @GetMapping(value = "/get")
    public AjaxResult getSequence(Sequence sequence) throws IOException {
        return sequenceService.getSequence(sequence);
    }
    @Log(title = "通过字符串或者文件搜索", businessType = BusinessType.VIEWED)
    @ApiOperation(value = "通过字符串或者文件搜索")
    @PostMapping(value = "/search")
    public AjaxResult search(Long id, MultipartFile file, String str,String featureName) throws IOException {
        if(StringUtils.isEmpty(str) && StringUtils.isEmpty(featureName)){
            InputStream is = file.getInputStream();
            str = IOUtils.toString(is,"utf-8");
            String strs[] = str.split("\r?\n");
            StringBuilder sb = new StringBuilder();
            for (String s : strs) {
                if(s.startsWith(">")){
                    continue;
                }
                sb.append(s);
            }
            str = sb.toString();
        }
        return sequenceService.search(str,id,featureName);
    }
    @Log(title = "打包", businessType = BusinessType.INSERT)
    @ApiOperation(value = "打包")
    @RequiresPermissions("programme:programme:pack")
    @PostMapping(value = "/pack")
    public AjaxResult pack(@RequestBody Pack pack) {
        List<String> programmeIdList = pack.getProgrammeIdList();
        List<String> packTypeList = pack.getPackTypeList();
        if(programmeIdList==null || packTypeList==null||programmeIdList.isEmpty()||packTypeList.isEmpty()){
            return AjaxResult.error("参数错误");
        }
        for (String programmeId : programmeIdList) {
            sequenceService.pack(programmeId,packTypeList);
        }
        return AjaxResult.success();
    }
    @Log(title = "选择文件", businessType = BusinessType.INSERT)
    @ApiOperation(value = "选择文件")
    @PostMapping(value = "/chooseFile")
    public AjaxResult chooseFile(@RequestBody Programme programme) {
        return sequenceService.chooseFile(programme.getId(),programme.getSourceFileName());
    }
    @Log(title = "打包下载", businessType = BusinessType.VIEWED)
    @ApiOperation(value = "打包下载")
    @RequiresPermissions("programme:programme:download")
    @GetMapping(value = "/pack/download")
    public ResponseEntity<?> packDownload(String programmeId) throws IOException {
        return sequenceService.packDownload(programmeId);
    }
    @Log(title = "操作列表", businessType = BusinessType.VIEWED)
    @ApiOperation(value = "操作列表")
    @GetMapping(value = "/operate/list")
    public TableDataInfo listSequenceOperate(Long sequenceId) {
        startPage();
        List<SequenceOperate> list =sequenceOperateService.listSequenceOperate(new SequenceOperate().setSequenceId(sequenceId));
        return getDataTable(list);
    }

//    @ApiOperation(value = "保存所有操作(包括rollback),已弃用")
//    @PostMapping(value = "/operate/saveAll")
//    @Transactional(rollbackFor = Exception.class)
//    public AjaxResult saveOperateAll(@RequestBody OperateAll operateAll) {
//        AjaxResult ajaxResult = new AjaxResult(HttpStatus.ERROR,"无新操作");
//        if(operateAll.getDelList().isEmpty()&&operateAll.getSaveList().isEmpty()){
//            return ajaxResult;
//        }
//        if(!operateAll.getSaveList().isEmpty()){
//            ajaxResult = sequenceOperateService.saveList(operateAll.getSaveList(),operateAll.getSequenceId());
//            if(ajaxResult.isError()){
//                return ajaxResult;
//            }
//        }
//        if(!operateAll.getDelList().isEmpty()){
//            ajaxResult = sequenceOperateService.removeList(operateAll.getDelList(),operateAll.getSequenceId());
//            if(ajaxResult.isError()){
//                return ajaxResult;
//            }
//        }
//        // 前端会处理好,这里只需要将删除的放在前面就行
//        operateAll.getDelList().addAll(operateAll.getSaveList());
//        ajaxResult = sequenceOperateService.operateSequenceFile(operateAll.getDelList(),operateAll.getSequenceId());
//        return ajaxResult;
//    }
    @Log(title = "保存序列操作", businessType = BusinessType.INSERT)
    @ApiOperation(value = "保存操作")
    @PostMapping(value = "/operate")
    public AjaxResult saveOperate(@RequestBody SequenceOperate sequenceOperate) {
        if(!OperateEnum.CUT.getValue().equalsIgnoreCase(sequenceOperate.getType())&&
                !OperateEnum.INSERT.getValue().equalsIgnoreCase(sequenceOperate.getType())&&
                !OperateEnum.REPLACE.getValue().equalsIgnoreCase(sequenceOperate.getType())){
            return AjaxResult.error("操作失败,不支持该类型");
        }
        if(!sequenceOperateService.checkCanOperate(sequenceOperate)){
            return AjaxResult.error("该区间不可以操作");
        }
        List<SequenceOperate> list = new ArrayList<>();
        list.add(sequenceOperate);
        if(sequenceOperate.getStart().equals(sequenceOperate.getEnd())){
            sequenceOperate.setEnd(sequenceOperate.getEnd()+1);
        }
        sequenceOperate.setNeedSetPreSequence(true);
        sequenceOperate.setCanRollback(true);
        sequenceOperateService.operateSequenceFile(list,sequenceOperate.getSequenceId(),false);
//        sequenceOperateService.getOperateSource(sequenceOperate.getSequenceId());
        return AjaxResult.success("操作成功",sequenceOperate);
    }
    @Log(title = "rollback", businessType = BusinessType.DELETE)
    @ApiOperation(value = "rollback")
    @DeleteMapping(value = "/operate/rollback")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult rollback(Long sequenceId,Long id) {
        return sequenceOperateService.rollback(sequenceId,id);
    }
}
